
package com.hlkj.pay.app.common.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.date.DateUtils;
import com.hlkj.framework.extension.executor.ExtensionExecutor;
import com.hlkj.framework.extension.scenario.BizScenario;
import com.hlkj.pay.app.common.IUploadService;
import com.hlkj.pay.app.common.OssExtPt;
import com.hlkj.pay.app.common.ext.CommonExtConstant;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.dto.common.StorageConfig;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.service.common.IPlatFormConfigService;
import com.hlkj.pay.util.RequestUtils;

import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/13 15:19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UploadServiceImpl implements IUploadService {

    private final ExtensionExecutor extensionExecutor;

    private final IPlatFormConfigService platFormConfigService;

    @Value("${hlkj.upload.prefix}")
    public String uploadPrefix;

    @Override
    public CommonResult<String> upload(MultipartFile multipartFile, CommonEnum.OssEnum ossEnum) {
        StorageConfig storageConfig = platFormConfigService.getStorageConfig();
        String key = buildSaveName(multipartFile);
        String url;
        try {
            url = extensionExecutor.execute(OssExtPt.class, BizScenario.valueOf(storageConfig.getEngine()), ex -> {
                try {
                    return ex.upload(multipartFile, ossEnum, key, storageConfig);
                }
                catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (Exception e) {
            log.error("文件上传失败 message:{}", e, e.getMessage());
            return CommonResult.error(CommonResultCode.FILE_UPLOAD_ERROR);
        }
        log.info("file 文件上传返回url:{}", url);
        return CommonResult.success(url);
    }

    @Override
    public CommonResult<String> upload(byte[] fileArray, CommonEnum.OssEnum ossEnum) {
        if (fileArray == null || fileArray.length == 0) {
            log.error("byte 文件上传 参数错误:fileArray为空");
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
        }
        log.info("byte 文件上传返回 fileArray-length:{}", fileArray.length);
        StorageConfig storageConfig = platFormConfigService.getStorageConfig();
        String key = buildByteName(ossEnum);
        String url;
        try {
            url = extensionExecutor.execute(OssExtPt.class, BizScenario.valueOf(storageConfig.getEngine()), ex -> {
                try {
                    return ex.upload(fileArray, ossEnum, key, storageConfig);
                }
                catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (Exception e) {
            log.error("文件上传失败 message:{}", e, e.getMessage());
            return CommonResult.error(CommonResultCode.FILE_UPLOAD_ERROR);
        }
        log.info("byte 文件上传返回url:{}", url);
        return CommonResult.success(url);
    }

    @Override
    public CommonResult<String> uploadLocalFile(byte[] fileArray, String fileName, CommonEnum.OssEnum ossEnum) {
        StorageConfig storageConfig = platFormConfigService.getStorageConfig();
        String key = buildByteName(ossEnum, fileName);
        String url;
        try {
            url = extensionExecutor.execute(OssExtPt.class, BizScenario.valueOf(CommonExtConstant.CHANNEL_LOCAL), ex -> {
                try {
                    return ex.upload(fileArray, ossEnum, key, storageConfig);
                }
                catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (Exception e) {
            log.error("本地文件上传失败 message:{}", e, e.getMessage());
            return CommonResult.error(CommonResultCode.FILE_UPLOAD_ERROR);
        }
        log.info("本地 文件上传返回url:{}", url);
        return CommonResult.success(url);
    }

    @Override
    public CommonResult<String> uploadLocalFileZip(List<String> fileList, String fileName) {
        StorageConfig storageConfig = platFormConfigService.getStorageConfig();
        CommonEnum.OssEnum ossEnum = CommonEnum.OssEnum.ZIP;
        String key = buildByteName(ossEnum, fileName);
        String url;
        try {
            url = extensionExecutor.execute(OssExtPt.class, BizScenario.valueOf(CommonExtConstant.CHANNEL_LOCAL), ex -> {
                try {
                    return ex.uploadZip(fileList, ossEnum, key, storageConfig);
                }
                catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (Exception e) {
            log.error("zip文件上传失败 message:{}", e, e.getMessage());
            return CommonResult.error(CommonResultCode.FILE_UPLOAD_ERROR);
        }
        log.info("zip文件上传返回url:{}", url);
        return CommonResult.success(url);
    }

    @Override
    public CommonResult<String> uploadSecret(MultipartFile multipartFile) {
        StorageConfig storageConfig = platFormConfigService.getStorageConfig();
        String key = buildSecretName(multipartFile);
        String url;
        try {
            url = extensionExecutor.execute(OssExtPt.class, BizScenario.valueOf(CommonExtConstant.CHANNEL_LOCAL), ex -> {
                try {
                    return ex.upload(multipartFile, CommonEnum.OssEnum.SECRET, key, storageConfig);
                }
                catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (Exception e) {
            log.error("文件上传失败 message:{}", e, e.getMessage());
            return CommonResult.error(CommonResultCode.FILE_UPLOAD_ERROR);
        }
        log.info("secret 文件上传返回url:{}", url);
        return CommonResult.success(url);
    }

    /**
     * 转绝对路径 转前: uploads/11.png 转后: https://127.0.0.1/uploads/11.png
     *
     * @author fzr
     * @param url
     *            相对路径
     * @return String
     */
    public String toAbsoluteUrl(String url, StorageConfig storageConfig) {
        if (url == null || url.equals("")) {
            return "";
        }
        if (url.indexOf("/") != 0) {
            url = "/" + url;
        }
        String engine = storageConfig.getEngine();
        if (StringUtil.isEmpty(engine)) {
            engine = "local";
        }
        if (engine.equals("local")) {
            return RequestUtils.uri() + "/" + uploadPrefix + url;
        }
        return storageConfig.getDomain() + url;
    }

    /**
     * 获取带端口的请求地址 示例: https://127.0.0.1:8082
     *
     * @author fzr
     * @return String
     */
    public static String uri() {
        String domain = RequestUtils.domain();
        if (!Arrays.asList(443, 80, 0).contains(RequestUtils.port())) {
            domain += ":" + RequestUtils.port();
        }

        return domain;
    }

    /**
     * 生成文件名称
     *
     * @author fzr
     * @param multipartFile
     *            文件对象
     * @return String
     */
    private String buildSaveName(MultipartFile multipartFile) {
        String name = multipartFile.getOriginalFilename();
        String ext = Objects.requireNonNull(name).substring(name.lastIndexOf("."));
        String date = DateUtils.format(LocalDateTime.now(), "yyyyMMdd");
        return date + "/" + UUID.randomUUID() + ext.toLowerCase();
    }
    /**
     * 生成文件名称
     *
     * @author fzr
     * @param multipartFile
     *            文件对象
     * @return String
     */
    private String buildSecretName(MultipartFile multipartFile) {
        String name = multipartFile.getOriginalFilename();
        // String ext = Objects.requireNonNull(name).substring(name.lastIndexOf("."));
        String date = DateUtils.format(LocalDateTime.now(), "yyyyMMdd");
        return date + "/" + name;
    }

    /**
     * 生成文件名称
     *
     * @author fzr 文件对象
     * @return String
     */
    private String buildByteName(CommonEnum.OssEnum ossEnum) {
        String ext = ossEnum.getExt();
        String date = DateUtils.format(LocalDateTime.now(), "yyyyMMdd");
        return date + "/" + UUID.randomUUID() + ext.toLowerCase();
    }

    /**
     * 生成文件名称
     *
     * @author fzr 文件对象
     * @return String
     */
    private String buildByteName(CommonEnum.OssEnum ossEnum, String fileName) {
        String ext = ossEnum.getExt();
        String date = DateUtils.format(LocalDateTime.now(), "yyyyMMdd");
        if (StringUtils.hasText(fileName)) {
            return date + "/" + fileName + ext.toLowerCase();
        }
        return date + "/" + UUID.randomUUID() + ext.toLowerCase();
    }
}
